package com.fastjars.http;

import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fastjars.framework.pojo.Page;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * Resp
 *
 * @author Brant Liu <br> 邮箱：<br>lbf1988@qq.com <br>日期：<br>2018/08/24
 * @version 1.0.0
 */
public class Resp implements Serializable {
    private int                code;

    private String             msg;

    private Map<String,Object> data;

    private Map<String,Object> extend;

    /**
     * Fastjson自定义过滤器
     */
    @JSONField(serialize = false)
    private SerializeFilter[]  filters = new SerializeFilter[0];

    /**
     * 导入Fastjson默认过滤器
     */
    @JSONField(serialize = false)
    private SerializerFeature[] includeFeatures = new SerializerFeature[0];

    /**
     * 移除Fastjson默认过滤器
     */
    @JSONField(serialize = false)
    private SerializerFeature[] excludeFeatures = new SerializerFeature[0];

    private Resp(int code, String msg, Map<String, Object> body, Map<String, Object> extend, SerializeFilter[] filters, SerializerFeature[] includeFeatures, SerializerFeature[] excludeFeatures) {
        this.code = code;
        this.msg = msg;
        this.data = body;
        this.extend = extend;
        this.filters = filters;
        this.includeFeatures = includeFeatures;
        this.excludeFeatures = excludeFeatures;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public Map<String, Object> getData() {
        return data;
    }

    public Map<String, Object> getExtend() {
        return extend;
    }

    public SerializeFilter[] getFilters() {
        return filters;
    }

    public SerializerFeature[] getIncludeFeatures() {
        return includeFeatures;
    }

    public SerializerFeature[] getExcludeFeatures() {
        return excludeFeatures;
    }

    public static ResponseBuilder status(Status status) {
        Assert.notNull(status, "Resp.Status must be not null");
        return new DefaultResponseBuilder(status);
    }

    public static ResponseBuilder status(int value, String message) {
        Assert.isNull(Status.valueOf(value), "matching constant for " + value + " already exists");
        return new DefaultResponseBuilder(value, message);
    }

    public static ResponseBuilder success(){
        return status(Status.OK);
    }

    public static ResponseBuilder page(Page page){
        return success().page(page);
    }

    public static ResponseBuilder unauthorized() {
        return status(Status.UNAUTHORIZED);
    }

    public static ResponseBuilder userNotLogin() {
        return status(Status.USER_NOT_LOGIN);
    }

    public static ResponseBuilder userLocked() {
        return status(Status.USER_LOCKED);
    }

    public static ResponseBuilder userKickOutLogin() {
        return status(Status.USER_KICK_OUT_LOGIN);
    }

    public static ResponseBuilder userOtherLogin() {
        return status(Status.USER_OTHER_LOGIN);
    }

    public static ResponseBuilder userForbidden(){
        return status(Status.USER_FORBIDDEN);
    }

    public interface ResponseBuilder{
        ResponseBuilder page(Page page);

        /**
         * 添加keyValue
         * @param key
         * @param value
         * @return
         */
        ResponseBuilder putBody(String key, Object value);

        /**
         * 添加keyValue
         * @param key
         * @param value
         * @return
         */
        ResponseBuilder putExtend(String key, Object value);

        /**
         * 自定义过滤器
         *
         * @param filters
         * @return
         */
        ResponseBuilder filters(SerializeFilter... filters);

        /**
         * 导入默认过滤器
         *
         * @param features
         * @return
         */
        ResponseBuilder includeFeatures(SerializerFeature... features);

        /**
         * 移除默认过滤器
         *
         * @param features
         * @return
         */
        ResponseBuilder excludeFeatures(SerializerFeature... features);

        /**
         * 构建
         * @return
         */
        Resp build();
    }

    private static class DefaultResponseBuilder implements ResponseBuilder{
        private int    value;
        private String message;
        private Map<String, Object> body;
        private Map<String, Object> extend;
        private SerializeFilter[] filters = new SerializeFilter[0];
        private SerializerFeature[] includeFeatures = new SerializerFeature[0];
        private SerializerFeature[] excludeFeatures = new SerializerFeature[0];

        public DefaultResponseBuilder(Status status) {
            this.value = status.value;
            this.message = status.reasonPhrase;
        }

        public DefaultResponseBuilder(int value, String message) {
            this.value = value;
            this.message = message;
        }

        @Override
        public ResponseBuilder page(Page page) {
            putBody("content",page);
            return this;
        }

        @Override
        public ResponseBuilder putBody(String key, Object value) {
            if(null == this.body){
                body = new HashMap<>();
            }
            if (this.body.containsKey(key)) {
                throw new IllegalArgumentException("key[" + key + "] has already existed");
            }
            this.body.put(key, value);
            return this;
        }

        @Override
        public ResponseBuilder putExtend(String key, Object value) {
            if(null == this.extend){
                extend = new HashMap<>();
            }
            if (this.extend.containsKey(key)) {
                throw new IllegalArgumentException("key[" + key + "] has already existed");
            }
            this.extend.put(key, value);
            return this;
        }

        @Override
        public ResponseBuilder filters(SerializeFilter... filters) {
            if (null == filters) {
                return this;
            }
            int length = this.filters.length;
            SerializeFilter[] mFilters = new SerializeFilter[length + filters.length];
            System.arraycopy(this.filters, 0, mFilters, 0, length);
            System.arraycopy(filters, 0, mFilters, length, filters.length);
            this.filters = mFilters;
            return this;
        }

        @Override
        public ResponseBuilder includeFeatures(SerializerFeature... features) {
            if (null == features) {
                return this;
            }
            int length = this.includeFeatures.length;
            SerializerFeature[] mFeature = new SerializerFeature[length + features.length];
            System.arraycopy(this.includeFeatures, 0, mFeature, 0, length);
            System.arraycopy(features, 0, mFeature, length, features.length);
            this.includeFeatures = mFeature;
            return this;
        }

        @Override
        public ResponseBuilder excludeFeatures(SerializerFeature... features) {
            if (null == features) {
                return this;
            }
            int length = this.excludeFeatures.length;
            SerializerFeature[] mFeature = new SerializerFeature[length + features.length];
            System.arraycopy(this.excludeFeatures, 0, mFeature, 0, length);
            System.arraycopy(features, 0, mFeature, length, features.length);
            this.excludeFeatures = mFeature;
            return this;
        }

        @Override
        public Resp build() {
            return new Resp(this.value, this.message, this.body, this.extend, this.filters, this.includeFeatures, this.excludeFeatures);
        }
    }

    public enum Status{
        OK(200, "success"),
        BAD_REQUEST(400, "Bad Request"),
        UNAUTHORIZED(401, "Unauthorized"),
        FORBIDDEN(403, "Forbidden"),
        NOT_FOUND(404, "Not Found"),
        REQUEST_TIMEOUT(408, "Request Timeout"),
        INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
        /**
         * ==========
         * 成功请求 200 + 1没有登录 + 异常代码
         * ==========
         * */
        /**
         * 没有登录
         */
        USER_NOT_LOGIN(2001,"\\u6ca1\\u6709\\u767b\\u5f55"),
        /**
         * 账户被锁定
         */
        USER_LOCKED(20010,"\\u8d26\\u6237\\u88ab\\u9501\\u5b9a"),
        /**
         * 您已经被强制下线，请重新登录
         */
        USER_KICK_OUT_LOGIN(20011,"\\u60a8\\u5df2\\u7ecf\\u88ab\\u5f3a\\u5236\\u4e0b\\u7ebf\\uff0c\\u8bf7\\u91cd\\u65b0\\u767b\\u5f55"),
        /**
         * 您已经在其他地方登录，请重新登录
         */
        USER_OTHER_LOGIN(20012,"\\u60a8\\u5df2\\u7ecf\\u5728\\u5176\\u4ed6\\u5730\\u65b9\\u767b\\u5f55\\uff0c\\u8bf7\\u91cd\\u65b0\\u767b\\u5f55"),
        /**
         * 用户被禁用
         */
        USER_FORBIDDEN(20013,"\\u7528\\u6237\\u88ab\\u7981\\u7528"),
        /**
         * 参数有误
         */
        PARAMETER_ERROR(2002,"\\u53c2\\u6570\\u6709\\u8bef"),
        /**
         * 业务异常
         */
        BUSINESS_ERROR(2003,"\\u4e1a\\u52a1\\u5f02\\u5e38");

        private final int value;
        private final String reasonPhrase;

        Status(int value, String reasonPhrase) {
            this.value = value;
            this.reasonPhrase = reasonPhrase;
        }

        public int getValue() {
            return value;
        }

        public String getReasonPhrase() {
            return reasonPhrase;
        }

        public static Status valueOf(int statusCode) {
            Status status = resolve(statusCode);
            if (status == null) {
                throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");
            }
            return status;
        }

        @Nullable
        public static Status resolve(int statusCode) {
            for (Status status : values()) {
                if (status.value == statusCode) {
                    return status;
                }
            }
            return null;
        }
    }
}
